#include "sv2_camera_base.h"


#define SV2_MAX_FRAMES 52000
typedef unsigned char byte;


namespace sv2 {
CameraBase::CameraBase(CameraType type, int id)
{
  this->_is_running = false;
  this->_is_updated = false;
  this->_type = type;
  
  this->_width = -1;
  this->_height = -1;
  this->_fps = -1;
  this->_ip = "192.168.2.64";
  this->_port = -1;
  this->_brightness = -1;
  this->_contrast = -1;
  this->_saturation = -1;
  this->_hue = -1;
  this->_exposure = -1;
  this->_fourcc = "MJPG";

  this->open(type, id);
}
CameraBase::~CameraBase()
{
  this->_is_running = false;
  // this->_tt.join();
}
std::string CameraBase::getFourcc()
{
  return this->_fourcc;
}
void CameraBase::setFourcc(std::string fourcc)
{
  this->_fourcc = fourcc;
}
void CameraBase::setWH(int width, int height)
{
  this->_width = width;
  this->_height = height;
}
void CameraBase::setFps(int fps)
{
  this->_fps = fps;
}
void CameraBase::setIp(std::string ip)
{
  this->_ip = ip;
}
void CameraBase::setRtspUrl(std::string rtsp_url)
{
  this->_rtsp_url = rtsp_url;
}
void CameraBase::setVideoPath(std::string video_path)
{
  this->_video_path = video_path;
}
void CameraBase::setPort(int port)
{
  this->_port = port;
}
void CameraBase::setBrightness(double brightness)
{
  this->_brightness = brightness;
}
void CameraBase::setContrast(double contrast)
{
  this->_contrast = contrast;
}
void CameraBase::setSaturation(double saturation)
{
  this->_saturation = saturation;
}
void CameraBase::setHue(double hue)
{
  this->_hue = hue;
}
void CameraBase::setExposure(double exposure)
{
  this->_exposure = exposure;
}

int CameraBase::getW()
{
  return this->_width;
}
int CameraBase::getH()
{
  return this->_height;
}
int CameraBase::getFps()
{
  return this->_fps;
}
std::string CameraBase::getIp()
{
  return this->_ip;
}
int CameraBase::getPort()
{
  return this->_port;
}
double CameraBase::getBrightness()
{
  return this->_brightness;
}
double CameraBase::getContrast()
{
  return this->_contrast;
}
double CameraBase::getSaturation()
{
  return this->_saturation;
}
double CameraBase::getHue()
{
  return this->_hue;
}
double CameraBase::getExposure()
{
  return this->_exposure;
}
bool CameraBase::isRunning()
{
  return this->_is_running;
}

void CameraBase::openImpl()
{
}
void CameraBase::open(CameraType type, int id)
{
  this->release();
  this->_type = type;
  this->_camera_id = id;

  openImpl();

  if (this->_cap.isOpened())
  {
    std::cout << "Camera opened!" << std::endl;
    this->_is_running = true;
    this->_tt = std::thread(&CameraBase::_run, this);
    this->_tt.detach();
  }
  else if (type != CameraType::NONE)
  {
    std::cout << "Camera can NOT open!" << std::endl;
  }
}
void CameraBase::_run()
{
  while (this->_is_running && this->_cap.isOpened())
  {
    if (this->_type != CameraType::VIDEO || this->_is_updated == false)
    {
      this->_cap >> this->_frame;
      this->_is_updated = true;
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(2));
  }
}
bool CameraBase::read(cv::Mat& image)
{
  if (this->_type != CameraType::NONE)
  {
    int n_try = 0;
    while (n_try < 5000)
    {
      if (this->_is_updated)
      {
        this->_frame.copyTo(image);
        this->_is_updated = false;
        break;
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(2));
      n_try ++;
    }
  }
  if (image.cols == 0 || image.rows == 0)
  {
    throw std::runtime_error("SpireCV 2.0 (101) Camera cannot OPEN, please check CAMERA_ID or CAMERA_IP!");
  }
  return image.cols > 0 && image.rows > 0;
}
void CameraBase::release()
{
  this->_is_running = false;
  this->_is_updated = false;
  if (this->_cap.isOpened())
    this->_cap.release();
}

}

